using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web.Routing;
using System.Web.Mvc;
using BrettM.Reflection;
using BrettM.Restful.SDK;

namespace BrettM.Web.Restful
{
    public static class Extensions
    {

        private static object GetConstraint(Type constraint)
        {
            if (constraint == null) return null;

            var o = Activator.CreateInstance(constraint) as IConstraint;
            return o == null ? null : o.GetConstraint();
        }

        public static IEnumerable<RestInfo> GetRESTfulAttributes(this IRestController controller)
        {
            if (controller == null)
                throw new ArgumentNullException("controller");

            var type = controller.GetType();

            return (from method in type.GetMethods()
                    from attribute in
                        method.GetCustomAttributes(typeof(RestfulAttribute), false).Cast<RestfulAttribute>()
                    select new RestInfo()
                               {
                                   Description = "",
                                   Method = method,
                                   HttpVerb = attribute.HttpVerb,
                                   //Url = controller.GetResourceItemName(attribute.Url)
                                   Url = attribute.Url,
                                   Constraint = GetConstraint(attribute.ConstraintType)
                               }
                    ).ToList();
        }

        /// <summary>
        /// Registers routes for attributed restul controllers
        /// </summary>
        /// <param name="routes"></param>
        /// <param name="controller"></param>
        public static void MapRoute(this RouteCollection routes, IRestController controller)
        {
            if (controller == null) throw new ArgumentNullException("controller");

            var type = controller.GetType();

            var controllerName = type.Name;
            if (controllerName.EndsWith("Controller", StringComparison.InvariantCultureIgnoreCase))
            {
                controllerName = controllerName.Substring(0, controllerName.Length - 10);
            }


            foreach (var info in controller.GetRESTfulAttributes())
            {
                var routeName = string.Format("{0}{1}", type.Name, info.Method.Name);


                Trace.WriteLine(string.Format("MapRoute {{ url=\"{0} {1}\" controller=\"{2}\" action=\"{3}\" }}", info.HttpVerb.ToString().ToUpper(), info.Url, controllerName, info.Method.Name));
                
                routes.MapRoute(
                    routeName
                    , info.Url
                    , new { controller = controllerName, action = info.Method.Name }
                    , TypeMerger.MergeTypes(new { httpVerbs = new HttpVerbConstraint(info.HttpVerb) }, info.Constraint)
                    , new string[] { type.Namespace });

            }
        }
    }
}
